package com.ruiao.car.utils;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.thymeleaf.util.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

@Slf4j
public class ShandwSignUtils {


    public static String HMACSHA256(byte[] data, byte[] key) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(signingKey);
            return byte2hex(mac.doFinal(data));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static boolean checkSign(Map<String, Object> params, String sign,String key) {
        String clientSign = geSign(params,key);
        if (clientSign.equals(sign)) {
            return true;
        }
        log.error("签名错误{}->{}", clientSign, sign);
        return false;
    }

    public static String geSign(Map<String, Object> params, String key) {
        //避免字段冲突
        if (params != null) {
            params.remove("sign");
        }

        //获取签名
        String[] sortParam = ShandwSignUtils.sort(params);
        String param = "";
        for (int i = 0; i < sortParam.length; i++) {

            //这里兼容int类型被转化为dubbo，导致签名错误
            Object oc = params.get(sortParam[i]);
            if (oc instanceof Number) {
                if (((Number) oc).longValue() == ((Number) oc).doubleValue()) {
                    oc = String.valueOf(((Number) oc).longValue());
                }
            }
            if (i == 0) {
                param = sortParam[i] + "=" + oc;
            } else {
                param = param + "&" + sortParam[i] + "=" + oc;
            }
        }

        if (!StringUtils.isEmpty(key)) {
            param = param + "&key=" + key;
        }

        log.info("签名字段{},签名后{}", param, MD5Utils.getMD5String(param));
        return MD5Utils.getMD5String(param);
    }

    public static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1) {
                hs.append('0');
            }
            hs.append(stmp);
        }
        return hs.toString().toUpperCase();
    }


    public static String[] sort(Map<String, Object> map) {
        String[] strsTrue = map.keySet().toArray(new String[map.keySet().size()]);
        System.out.println(new Gson().toJson(strsTrue));
        System.out.println(new Gson().toJson(getUrlParam(strsTrue)));
        return strsTrue;
    }


    /**
     * 对字符串数组进行排序
     *
     * @param keys
     * @return
     */
    public static String[] getUrlParam(String[] keys) {

        for (int i = 0; i < keys.length - 1; i++) {
            for (int j = 0; j < keys.length - i - 1; j++) {
                String pre = keys[j];
                String next = keys[j + 1];
                if (isMoreThan(pre, next)) {
                    String temp = pre;
                    keys[j] = next;
                    keys[j + 1] = temp;
                }
            }
        }
        return keys;
    }

    /**
     * 比较两个字符串的大小，按字母的ASCII码比较
     *
     * @param pre
     * @param next
     * @return
     */
    private static boolean isMoreThan(String pre, String next) {
        if (null == pre || null == next || "".equals(pre) || "".equals(next)) {
            return false;
        }

        char[] c_pre = pre.toCharArray();
        char[] c_next = next.toCharArray();

        int minSize = Math.min(c_pre.length, c_next.length);

        for (int i = 0; i < minSize; i++) {
            if ((int) c_pre[i] > (int) c_next[i]) {
                return true;
            } else if ((int) c_pre[i] < (int) c_next[i]) {
                return false;
            }
        }
        if (c_pre.length > c_next.length) {
            return true;
        }

        return false;
    }


}
